package com.inspur.dgov.bsp.application.controller;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.inspur.dgov.bsp.application.entity.PubRole;
import com.inspur.dgov.bsp.application.entity.PubRoleResource;
import com.inspur.dgov.bsp.application.service.PubRoleResourceService;
import com.inspur.dgov.bsp.application.service.PubRoleService;
import com.inspur.dgov.bsp.application.service.TreeService;
import com.inspur.dgov.bsp.application.vo.RoleVO;
import com.inspur.dgov.bsp.application.wrapper.PubRoleWrapper;
import com.inspur.dgov.common.secure.dto.SecureUser;
import com.inspur.dgov.common.secure.utils.SecureUtil;
import com.inspur.dgov.common.tool.api.R;
import com.inspur.dgov.common.tool.constant.AppConstant;
import com.inspur.dgov.common.tool.node.TreeNode;
import com.inspur.dgov.common.tool.node.TreeNodeUtil;
import com.inspur.dgov.common.tool.utils.UniqueIdGenerator;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色信息 前端控制器
 * </p>
 *
 * @author chiyupei
 * @since 2020-04-17
 */
@RestController
@RequestMapping("/role")
@Api(value = "角色信息", tags = "角色信息")
public class PubRoleController {

    @Value("${tenant.default.id}")
    private String defaultTenantId;

    @Autowired
    private PubRoleService pubRoleService;

    @Autowired
    private TreeService treeService;

    @Autowired
    private PubRoleResourceService pubRoleResourceService;

    @Value("${role.default.id}")
    private String[] defaultSystemRoleId;

    /**
     * 角色分页列表
     *
     * @param query
     * @param page
     * @return
     */
    @PostMapping("/page")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "角色编码", paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "name", value = "角色名称", paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "type", value = "角色类型", paramType = "query", dataType = "string")
    })
    @ApiOperation(value = "角色信息列表", notes = "传入角色源编码、角色名称或角色类型", position = 1)
    public R<IPage<RoleVO>> page(@ApiIgnore @RequestParam Map<String, Object> query, Page page) {
        SecureUser curUser = SecureUtil.getUser();
        String tenantId = curUser.getTenantId();
        if (!StrUtil.equals(this.defaultTenantId, tenantId)) {
            query.put("tenantId", tenantId);
        }
        IPage<PubRole> pages = this.pubRoleService.selectRolePage(page, query);
        return R.data(PubRoleWrapper.build().pageVO(pages));
    }

    /**
     * 父级角色
     */
    @GetMapping("/parent")
    @ApiOperation(value = "查询父级角色", notes = "传入应用ID", position = 2)
    public R<List<TreeNode>> parent(@RequestParam(value = "appId", required = false) String appId) {
        List<TreeNode> tree = new ArrayList<>();
        Map<String, Object> param = new HashMap<>();
        tree.addAll(this.treeService.roleParent(param));
        return R.data(TreeNodeUtil.merge(tree));
    }

    /**
     * 新增角色
     *
     * @param role
     * @return
     */
    @PostMapping("/add")
    @ApiOperation(value = "新增角色", notes = "传入角色信息", position = 3)
    public R add(@RequestBody PubRole role) {
        SecureUser curUser = SecureUtil.getUser();
        LocalDateTime now = LocalDateTime.now();
        Long id = UniqueIdGenerator.generateId();
        role.setId(id);
        role.setCreator(Long.valueOf(curUser.getUserId()));
        role.setCreateTime(now);
        role.setStatus(AppConstant.DB_STATUS_NORMAL);
        role.setTenantId(Long.valueOf(curUser.getTenantId()));
        boolean ret = this.pubRoleService.save(role);
        return R.status(ret);
    }

    /**
     * 更新角色
     *
     * @param role
     * @return
     */
    @PostMapping("/update")
    @ApiOperation(value = "更新角色", notes = "传入角色信息", position = 4)
    public R update(@RequestBody PubRole role) {
        SecureUser curUser = SecureUtil.getUser();
        LocalDateTime now = LocalDateTime.now();
        role.setUpdator(Long.valueOf(curUser.getUserId()));
        role.setUpdateTime(now);
        boolean ret = this.pubRoleService.updateById(role);
        return R.status(ret);
    }

    /**
     * 删除角色
     */
    @PostMapping("/remove")
    @ApiOperation(value = "删除角色", notes = "传入角色信息", position = 5)
    public R remove(@RequestBody PubRole role) {
        //检查是否有下级
        QueryWrapper<PubRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(PubRole::getParentId, role.getId());
        int count = this.pubRoleService.count(queryWrapper);
        if (count > 0) {
            return R.fail("存在下级角色，不能删除");
        }
        //系统角色不能删除
        if (ArrayUtil.contains(this.defaultSystemRoleId, role.getId().toString())) {
            return R.fail("系统角色不能删除");
        }
        //删除角色资源关系
        UpdateWrapper<PubRoleResource> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(PubRoleResource::getRoleId, role.getId());
        this.pubRoleResourceService.remove(updateWrapper);
        //删除角色
        boolean ret = this.pubRoleService.removeById(role);
        return R.status(ret);
    }

    /**
     * 获取角色资源配置
     *
     * @param roleId
     * @return
     */
    @GetMapping("/roleResource")
    @ApiOperation(value = "角色所分配的资源", notes = "角色所分配的资源", position = 6)
    public R<List<String>> roleResource(@RequestParam(value = "roleId", required = true) String roleId) {
        List<PubRoleResource> roleResource = this.pubRoleResourceService.list(Wrappers.<PubRoleResource>query().lambda()
                .eq(PubRoleResource::getRoleId, roleId));
        List<String> list = roleResource.stream().map(roleMenu -> StrUtil.toString(roleMenu.getResId())).collect(Collectors.toList());
        return R.data(list);
    }

    /**
     * 角色权限设置
     *
     * @param json
     * @return
     */
    @PostMapping("/grant")
    @ApiOperation(value = "角色权限设置", notes = "传入角色ID、资源IDS", position = 7)
    public R grant(@RequestBody JSONObject json) {
        boolean ret = this.pubRoleService.grant(json.getString("roleId"), json.getString("menuIds"));
        return R.status(ret);
    }

    /**
     * 获取用户角色树
     */
    @GetMapping("/grantRole")
    @ApiOperation(value = "角色分配树形结构", notes = "角色分配树形结构")
    public R<List<TreeNode>> grantRole() {
        SecureUser curUser = SecureUtil.getUser();
        //获取当前登录用户角色权重
        String tenantId = curUser.getTenantId();
        PubRole role = new PubRole();
        role.setTenantId(Long.valueOf(tenantId));
        QueryWrapper<PubRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(PubRole::getTenantId, tenantId);
        queryWrapper.lambda().in(PubRole::getId, StrUtil.split(curUser.getRoleId(), ','));
        queryWrapper.lambda().orderByAsc(PubRole::getWeight);
        List<PubRole> list = this.pubRoleService.list(queryWrapper);
        if (list.size() > 0) {
            role = list.get(0);
        }

        List<TreeNode> tree = this.treeService.grantRole(role);
        return R.data(TreeNodeUtil.merge(tree));
    }
}
